//
//  List.m
//  XLForm ( https://github.com/xmartlabs/XLForm )
//
//  Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com )
//
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#import "UIView+XLFormAdditions.h"
#import "List.h"
#import "UIView+XLFormAdditions.h"
#import "XLForm.h"
@interface List()<UITableViewDataSource, UITableViewDelegate,
FormDelegate,
UITextFieldDelegate,UITextViewDelegate>
{
    NSNumber *_oldBottomTableContentInset;
    CGRect _keyboardFrame;
}
@property UITableViewStyle tableViewStyle;
@property (nonatomic) XLFormRowNavigationAccessoryView * navigationAccessoryView;

@end

@implementation List

@synthesize form = _form;
@synthesize tableView = _tableView;

#pragma mark - Initialization

-(instancetype)init
{
    self = [super init];
    if (self){
        _tableViewStyle = UITableViewStylePlain;
        self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
    }
    return self;
}

- (void)dealloc
{
    if (_tableView)
    {
        _tableView.delegate = nil;
        _tableView.dataSource = nil;
    }
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    if (self.form)
    {
        self.form.delegate = self;
    }
    _oldBottomTableContentInset = nil;
    
    [self initSubviews];
    [self initDataSource];
}

-(void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    NSIndexPath *selected = [self.tableView indexPathForSelectedRow];
    if (selected){
        Row * row = [self.form rowAtIndex:selected];
        [row update];
        [row select];
        [row deselect];
    }
    
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(contentSizeCategoryChanged:)
                                                 name:UIContentSizeCategoryDidChangeNotification
                                               object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillShow:)
                                                 name:UIKeyboardWillShowNotification
                                               object:nil];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardWillHide:)
                                                 name:UIKeyboardWillHideNotification
                                               object:nil];

}

-(void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:UIContentSizeCategoryDidChangeNotification
                                                  object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:UIKeyboardWillShowNotification
                                                  object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:UIKeyboardWillHideNotification
                                                  object:nil];
}

- (void)contentSizeCategoryChanged:(NSNotification *)notification
{
    [self.tableView reloadData];
}

-(void) initSubviews
{
    [self.view addSubview:self.tableView];
    [self.tableView makeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(self.view);
    }];
}

-(void) initDataSource
{
    
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}

#pragma mark - CellClasses

-(NSMutableDictionary *)cellClassesForRowTypes
{
    static NSMutableDictionary * _cellClassesForRowDescriptorTypes;

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
//        _cellClassesForRowDescriptorTypes = [@{XLFormRowDescriptorTypeText:[XLFormTextFieldCell class],
//                                               XLFormRowDescriptorTypeName: [XLFormTextFieldCell class],
//                                               XLFormRowDescriptorTypePhone:[XLFormTextFieldCell class],
//                                               XLFormRowDescriptorTypeURL:[XLFormTextFieldCell class],
    });
    return _cellClassesForRowDescriptorTypes;
}

#pragma mark - FormDelegate

/*
 1、beginUpdates 和 endUpdates必须成对使用
 2、使用beginUpdates和endUpdates可以在改变一些行（row）的高度时自带动画，并且不需要Reload row（不用调用cellForRow，仅仅需要调用heightForRow，这样效率最高）。
 3、在beginUpdates和endUpdates中执行insert,delete,select,reload row时，动画效果更加同步和顺滑，否则动画卡顿且table的属性（如row count）可能会失效。
 4、在beginUpdates 和 endUpdates中执行 reloadData 方法和直接reloadData一样，没有相应的中间动画。
 */
-(void)rowHasBeenAdded:(Row *)formRow atIndexPath:(NSIndexPath *)indexPath
{
    [self.tableView beginUpdates];
    [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
    [self.tableView endUpdates];
}

-(void)rowHasBeenRemoved:(Row *)formRow atIndexPath:(NSIndexPath *)indexPath
{
    [self.tableView beginUpdates];
    [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
    [self.tableView endUpdates];
}

-(void)sectionHasBeenRemoved:(Section *)formSection atIndex:(NSUInteger)index
{
    [self.tableView beginUpdates];
    [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:index] withRowAnimation:UITableViewRowAnimationAutomatic];
    [self.tableView endUpdates];
}

-(void)sectionHasBeenAdded:(Section *)formSection atIndex:(NSUInteger)index
{
    [self.tableView beginUpdates];
    [self.tableView insertSections:[NSIndexSet indexSetWithIndex:index] withRowAnimation:UITableViewRowAnimationAutomatic];
    [self.tableView endUpdates];
}


#pragma mark - UITableViewDataSource

-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return [self.form.sections count];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    if (section >= self.form.sections.count){
        @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"" userInfo:nil];
    }
    return [[[self.form.sections objectAtIndex:section] rows] count];
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    Row * row = [self.form rowAtIndex:indexPath];
    [row update];
    return row.cell;
}

#pragma mark - UITableViewDelegate

-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    return [[self.form.sections objectAtIndex:section] title];
}

-(NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section
{
    return [[self.form.sections objectAtIndex:section] footerTitle];
}

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    Row *row = [self.form rowAtIndex:indexPath];
    CGFloat height = row.height;
    if (height > 0){
        return height;
    }
    return self.tableView.rowHeight;
}

-(CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    Row *rowDescriptor = [self.form rowAtIndex:indexPath];
    CGFloat height = rowDescriptor.height;
    if (height > 0){ //初始化为 -2
        return height;
    }
    if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")){
        return self.tableView.estimatedRowHeight;
    }
    return 44;
}

/*
     1. 取消选中状态
     2. 隐藏键盘
     3. 分发事件
 */
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    Row * row = [self.form rowAtIndex:indexPath];
    [row deselect];
    UITableViewCell<CellProtocol> * cell = row.cell;
    
    /*
     键盘事件流程：
     1. didSelectedRow  -> Cell :: becomeFirstResponder
     2. tableView.beginEditing
     3. cell -> inputAccessoryView
     4. resignFirsetResponder
     5. tableView.endEditing
     */
    if (!([cell cellCanBecomeFirstResponder] && [cell cellBecomeFirstResponder])){
        //becomeFirstResponder失败则收起键盘
        [self.tableView endEditing:YES];
    }
    [row didSelected];
}

#pragma mark - KeyBoard

-(UIView *)inputAccessoryViewForRow:(Row *)row
{
    if ((self.form.rowNavigationOptions & XLFormRowNavigationOptionEnabled) != XLFormRowNavigationOptionEnabled){
        return nil;
    }
    UITableViewCell<CellProtocol> * cell = row.cell;
    if (![cell cellCanBecomeFirstResponder]){
        return nil;
    }
    Row * previousRow = [self nextRowForRow:row
                              withDirection:XLFormRowNavigationDirectionPrevious];
    
    Row * nextRow = [self nextRowForRow:row
                          withDirection:XLFormRowNavigationDirectionNext];
    
    [self.navigationAccessoryView.previousButton setEnabled:(previousRow != nil)];
    [self.navigationAccessoryView.nextButton setEnabled:(nextRow != nil)];
    return self.navigationAccessoryView;
}

-(void)beginEditing:(Row *)row
{
    [row.cell highlight];
}

-(void)endEditing:(Row *)row
{
    [row.cell unhighlight];
}

- (void)keyboardWillShow:(NSNotification *)notification
{
    UIView * firstResponderView = [self.tableView findFirstResponder];
    UITableViewCell<CellProtocol> * cell = [firstResponderView cell];
    if (cell){
        NSDictionary *keyboardInfo = [notification userInfo];
        _keyboardFrame = [self.tableView.window convertRect:[keyboardInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue] toView:self.tableView.superview];
        CGFloat newBottomInset = self.tableView.frame.origin.y + self.tableView.frame.size.height - _keyboardFrame.origin.y;
        UIEdgeInsets tableContentInset = self.tableView.contentInset;
        UIEdgeInsets tableScrollIndicatorInsets = self.tableView.scrollIndicatorInsets;
        _oldBottomTableContentInset = _oldBottomTableContentInset ?: @(tableContentInset.bottom);
        if (newBottomInset > [_oldBottomTableContentInset floatValue]){
            tableContentInset.bottom = newBottomInset;
            tableScrollIndicatorInsets.bottom = tableContentInset.bottom;
            [UIView beginAnimations:nil context:nil];
            [UIView setAnimationDuration:[keyboardInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
            [UIView setAnimationCurve:[keyboardInfo[UIKeyboardAnimationCurveUserInfoKey] intValue]];
            self.tableView.contentInset = tableContentInset;
            self.tableView.scrollIndicatorInsets = tableScrollIndicatorInsets;
            NSIndexPath *selectedRow = [self.tableView indexPathForCell:cell];
            [self.tableView scrollToRowAtIndexPath:selectedRow atScrollPosition:UITableViewScrollPositionNone animated:NO];
            [UIView commitAnimations];
        }
    }
}

- (void)keyboardWillHide:(NSNotification *)notification
{
    UIView * firstResponderView = [self.tableView findFirstResponder];
    UITableViewCell<CellProtocol> * cell = [firstResponderView cell];
    if (cell){
        _keyboardFrame = CGRectZero;
        NSDictionary *keyboardInfo = [notification userInfo];
        UIEdgeInsets tableContentInset = self.tableView.contentInset;
        UIEdgeInsets tableScrollIndicatorInsets = self.tableView.scrollIndicatorInsets;
        tableContentInset.bottom = [_oldBottomTableContentInset floatValue];
        tableScrollIndicatorInsets.bottom = tableContentInset.bottom;
        _oldBottomTableContentInset = nil;
        [UIView beginAnimations:nil context:nil];
        [UIView setAnimationDuration:[keyboardInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
        [UIView setAnimationCurve:[keyboardInfo[UIKeyboardAnimationCurveUserInfoKey] intValue]];
        self.tableView.contentInset = tableContentInset;
        self.tableView.scrollIndicatorInsets = tableScrollIndicatorInsets;
        [UIView commitAnimations];
    }
}



#pragma mark - UITextFieldDelegate
- (BOOL)textFieldShouldClear:(UITextField *)textField
{
    return YES;
}

/*
 键盘Return事件处理：
     1. 有下一行，则下一行成为FirstResponder
     2. 没有下一行，则收起键盘
 */
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
    UITableViewCell<CellProtocol> * cell = [textField cell];
    Row * currentRow = cell.row;
    Row * nextRow = [self nextRowForRow:currentRow
                          withDirection:XLFormRowNavigationDirectionNext];
    if (nextRow){
        UITableViewCell<CellProtocol> * nextCell = nextRow.cell;
        if ([nextCell cellCanBecomeFirstResponder]){
            [nextCell cellBecomeFirstResponder];
            return YES;
        }
    }
    [self.tableView endEditing:YES];
    return YES;
}

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
    UITableViewCell<CellProtocol>* cell = textField.cell;
    Row * nextRow  = [self nextRowForRow:textField.cell.row
                           withDirection:XLFormRowNavigationDirectionNext];
    
    
    if ([cell conformsToProtocol:@protocol(XLFormReturnKeyProtocol)]) {
        textField.returnKeyType = nextRow ? ((id<XLFormReturnKeyProtocol>)cell).nextReturnKeyType : ((id<XLFormReturnKeyProtocol>)cell).returnKeyType;
    }
    else {
        textField.returnKeyType = nextRow ? UIReturnKeyNext : UIReturnKeyDefault;
    }
    return YES;
}

- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
{
    return YES;
}

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
    return YES;
}

- (void)textFieldDidBeginEditing:(UITextField *)textField
{
}

-(void)textFieldDidEndEditing:(UITextField *)textField
{
}

#pragma mark - UITextViewDelegate

- (BOOL)textViewShouldBeginEditing:(UITextView *)textView
{
    return YES;
}

-(void)textViewDidBeginEditing:(UITextView *)textView
{
}

-(void)textViewDidEndEditing:(UITextView *)textView
{
}

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
	return YES;
}

#pragma mark - UIScrollViewDelegate

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    //滑动时隐藏键盘
    [self.tableView endEditing:YES];
}

#pragma mark - Navigation Between Fields
-(void)rowNavigationAction:(UIBarButtonItem *)sender
{
    [self navigateToDirection:(sender == self.navigationAccessoryView.nextButton ? XLFormRowNavigationDirectionNext : XLFormRowNavigationDirectionPrevious)];
}

-(void)rowNavigationDone:(UIBarButtonItem *)sender
{
    [self.tableView endEditing:YES];
}

-(void)navigateToDirection:(XLFormRowNavigationDirection)direction
{
    UIView * firstResponder = [self.tableView findFirstResponder];
    UITableViewCell<CellProtocol> * currentCell = [firstResponder cell];
    NSIndexPath * currentIndexPath = [self.tableView indexPathForCell:currentCell];
    Row * currentRow = [self.form rowAtIndex:currentIndexPath];
    Row * nextRow = [self nextRowForRow:currentRow withDirection:direction];
    if (nextRow) {
        UITableViewCell<CellProtocol> * cell = (UITableViewCell<CellProtocol> *)nextRow.cell;
        if ([cell cellCanBecomeFirstResponder]){
            NSIndexPath * indexPath = [self.form indexPathOfRow:nextRow];
            [self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionNone animated:NO];
            [cell cellBecomeFirstResponder];
        }
    }
}

-(Row *)nextRowForRow:(Row*)currentRow withDirection:(XLFormRowNavigationDirection)direction
{
    if (!currentRow || (self.form.rowNavigationOptions & XLFormRowNavigationOptionEnabled) != XLFormRowNavigationOptionEnabled) {
        return nil;
    }
    Row * nextRow = (direction == XLFormRowNavigationDirectionNext) ? [self.form nextRowForRow:currentRow] : [self.form previousRowForRow:currentRow];
    if (!nextRow) {
        return nil;
    }
    if ([nextRow.cell conformsToProtocol:@protocol(XLFormInlineRowDescriptorCell)]) {
        id<XLFormInlineRowDescriptorCell> inlineCell = (id<XLFormInlineRowDescriptorCell>)nextRow.cell;
        if (inlineCell.inlineRowDescriptor){
            return [self nextRowForRow:nextRow withDirection:direction];
        }
    }
    XLFormRowNavigationOptions rowNavigationOptions = self.form.rowNavigationOptions;
    if ( ((rowNavigationOptions & XLFormRowNavigationOptionStopDisableRow) == XLFormRowNavigationOptionStopDisableRow)){
        return nil;
    }
    
    UITableViewCell<CellProtocol> * cell = (UITableViewCell<CellProtocol> *)nextRow.cell;
    if (((rowNavigationOptions & XLFormRowNavigationOptionSkipCanNotBecomeFirstResponderRow) != XLFormRowNavigationOptionSkipCanNotBecomeFirstResponderRow) && (![cell cellCanBecomeFirstResponder])){
        return nil;
    }
    if ([cell cellCanBecomeFirstResponder]){
        return nextRow;
    }
    return [self nextRowForRow:nextRow withDirection:direction];
}

#pragma mark - lazy load

-(void)setForm:(Form *)form
{
    _form.delegate = nil;
    _form.list = nil;
    [self.tableView endEditing:YES];
    _form = form;
    _form.delegate = self;
    _form.list = self;
    if ([self isViewLoaded]){
        [self.tableView reloadData];
    }
}

-(Form *)form
{
    return _form;
}

-(XLFormRowNavigationAccessoryView *)navigationAccessoryView
{
    if (_navigationAccessoryView) return _navigationAccessoryView;
    _navigationAccessoryView = [XLFormRowNavigationAccessoryView new];
    _navigationAccessoryView.previousButton.target = self;
    _navigationAccessoryView.previousButton.action = @selector(rowNavigationAction:);
    _navigationAccessoryView.nextButton.target = self;
    _navigationAccessoryView.nextButton.action = @selector(rowNavigationAction:);
    _navigationAccessoryView.doneButton.target = self;
    _navigationAccessoryView.doneButton.action = @selector(rowNavigationDone:);
    _navigationAccessoryView.tintColor = self.view.tintColor;
    return _navigationAccessoryView;
}

-(UITableView *) tableView
{
    if (!_tableView)
    {
        _tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:_tableViewStyle];
        _tableView.delegate = self;
        _tableView.dataSource = self;
        
        if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")){
            _tableView.rowHeight = UITableViewAutomaticDimension;
            _tableView.estimatedRowHeight = 44.0;
        }
    }
    return _tableView;
}
@end

